using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Net.Mail;
using System.Text;
using System.Web;
using BusinessLogic.Caching;
using BusinessLogic.Configuration.Settings;
using BusinessLogic.Data;
using BusinessLogic.Directory;
using BusinessLogic.Infrastructure;
using Common;
using Common.Utils;
using OpenPop.Mime;
using OpenPop.Pop3;
using OpenPop.Pop3.Exceptions;
using BusinessLogic.Customer;

namespace BusinessLogic.Messages
{
    /// <summary>
    /// Message service
    /// </summary>
    public partial class MessageService : IMessageService
    {
        #region Fields

        /// <summary>
        /// Object context
        /// </summary>
        private readonly DataMailDataContext _context;
        private readonly Pop3Client m_pop3Client;
        /// <summary>
        /// Cache manager
        /// </summary>
        private readonly ICacheManager _cacheManager;

        #endregion

        #region Ctor

        /// <summary>
        /// Ctor
        /// </summary>
        /// <param name="context">Object context</param>
        public MessageService(DataMailDataContext context)
        {
            this._context = context;
            this._cacheManager = new PayrollRequestCache();
            this.m_pop3Client = new Pop3Client();
        }

        #endregion

        #region Utilities

        private string Replace(string original, string pattern, string replacement)
        {
            if (IoC.Resolve<ISettingManager>().GetSettingValueBoolean("MessageTemplates.CaseInvariantReplacement"))
            {
                int count = 0;
                int position0 = 0;
                int position1 = 0;
                string upperString = original.ToUpper();
                string upperPattern = pattern.ToUpper();
                int inc = (original.Length / pattern.Length) * (replacement.Length - pattern.Length);
                char[] chars = new char[original.Length + Math.Max(0, inc)];
                while((position1 = upperString.IndexOf(upperPattern, position0)) != -1)
                {
                    for(int i = position0; i < position1; ++i)
                        chars[count++] = original[i];
                    for(int i = 0; i < replacement.Length; ++i)
                        chars[count++] = replacement[i];
                    position0 = position1 + pattern.Length;
                }
                if(position0 == 0) return original;
                for(int i = position0; i < original.Length; ++i)
                    chars[count++] = original[i];
                return new string(chars, 0, count);
            }
            else
            {
                return original.Replace(pattern, replacement);
            }
        }

        #endregion

        #region Methods

        #region Repository methods
       
        #endregion

        #region Workflow methods

      
        /// <summary>
        /// Sends an email
        /// </summary>
        /// <param name="subject">Subject</param>
        /// <param name="body">Body</param>
        /// <param name="from">From</param>
        /// <param name="to">To</param>
        /// <param name="emailAccount">Email account to use</param>
        public void SendEmail(string subject, string body, string from, string to, 
            EmailAccount emailAccount)
        {
            SendEmail(subject, body, new MailAddress(from), new MailAddress(to),
                new List<String>(), new List<String>(), emailAccount);
        }

        /// <summary>
        /// Sends an email
        /// </summary>
        /// <param name="subject">Subject</param>
        /// <param name="body">Body</param>
        /// <param name="from">From</param>
        /// <param name="to">To</param>
        /// <param name="emailAccount">Email account to use</param>
        public void SendEmail(string subject, string body, MailAddress from,
            MailAddress to, EmailAccount emailAccount)
        {
            SendEmail(subject, body, from, to, new List<String>(), new List<String>(), emailAccount);
        }

        /// <summary>
        /// Sends an email
        /// </summary>
        /// <param name="subject">Subject</param>
        /// <param name="body">Body</param>
        /// <param name="from">From</param>
        /// <param name="to">To</param>
        /// <param name="bcc">BCC</param>
        /// <param name="cc">CC</param>
        /// <param name="emailAccount">Email account to use</param>
        public void SendEmail(string subject, string body,
            MailAddress from, MailAddress to, List<string> bcc, 
            List<string> cc, EmailAccount emailAccount)
        {
            var message = new MailMessage();
            message.From = from;
            message.To.Add(to);
            if (null != bcc)
                foreach (string address in bcc)
                {
                    if (address != null)
                    {
                        if (!String.IsNullOrEmpty(address.Trim()))
                        {
                            message.Bcc.Add(address.Trim());
                        }
                    }
                }
            if (null != cc)
                foreach (string address in cc)
                {
                    if (address != null)
                    {
                        if (!String.IsNullOrEmpty(address.Trim()))
                        {
                            message.CC.Add(address.Trim());
                        }
                    }
                }
            message.Subject = subject;
            message.Body = body;
            message.IsBodyHtml = true;

            var smtpClient = new SmtpClient();
            smtpClient.UseDefaultCredentials = emailAccount.UseDefaultCredentials;
            smtpClient.Host = emailAccount.Host;
            smtpClient.Port = emailAccount.Port;
            smtpClient.EnableSsl = emailAccount.EnableSSL;
            if (emailAccount.UseDefaultCredentials)
                smtpClient.Credentials = CredentialCache.DefaultNetworkCredentials;
            else
                smtpClient.Credentials = new NetworkCredential(emailAccount.Username, emailAccount.Password);
            smtpClient.Send(message);
        }

        #endregion

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets a primary store currency
        /// </summary>
        public EmailAccount DefaultEmailAccount
        {
            get
            {
                return IoC.Resolve<ICompanyService>().GetAccount(16, 0); ;
            }
            set
            {
                if (value != null)
                    IoC.Resolve<ICompanyService>().GetAccount(16, 0);
            }
        }

        #endregion

        public Dictionary<int, Message> GetMessage(string popServer, int port, bool useSsl, string login, string password)
        {
            Dictionary<int, Message> messages = new Dictionary<int, Message>();
            try
            {
                if (m_pop3Client.Connected)
                    m_pop3Client.Disconnect();
                m_pop3Client.Connect(popServer, port, useSsl);
                m_pop3Client.Authenticate(login, password);
                int count = m_pop3Client.GetMessageCount();
                List<string> uids = m_pop3Client.GetMessageUids();
                int success = 0;
                int fail = 0;
                for (int i = count; i >= 1; i -= 1)
                {
                    try
                    {
                        Message message = m_pop3Client.GetMessage(i);
                        // Add the message to the dictionary from the messageNumber to the Message
                        messages.Add(i, message);
                        success++;
                    }
                    catch (Exception e)
                    {
                        //DefaultLogger.Log.LogError(                            "TestForm: Message fetching failed: " + e.Message + "\r\n" +                            "Stack trace:\r\n" +                            e.StackTrace);
                        fail++;
                    }
                }
            }
            catch (InvalidLoginException)
            {
                //MessageBox.Show(this, "The server did not accept the user credentials!", "POP3 Server Authentication");
            }
            catch (PopServerNotFoundException)
            {
                //MessageBox.Show(this, "The server could not be found", "POP3 Retrieval");
            }
            catch (PopServerLockedException)
            {
                //MessageBox.Show(this, "The mailbox is locked. It might be in use or under maintenance. Are you connected elsewhere?", "POP3 Account Locked");
            }
            catch (LoginDelayException)
            {
                //MessageBox.Show(this, "Login not allowed. Server enforces delay between logins. Have you connected recently?", "POP3 Account Login Delay");
            }
            catch (Exception e)
            {
                //MessageBox.Show(this, "Error occurred retrieving mail. " + e.Message, "POP3 Retrieval");
            }
            finally
            {

            }
            return messages;
        }
        public List<Message> FetchUnseenMessages(string hostname, int port, bool useSsl, string username, string password, List<string> seenUids)
        {
            // The client disconnects from the server when being disposed
            using (Pop3Client client = new Pop3Client())
            {
                // Connect to the server
                client.Connect(hostname, port, useSsl);

                // Authenticate ourselves towards the server
                client.Authenticate(username, password);

                // Fetch all the current uids seen
                List<string> uids = client.GetMessageUids();

                // Create a list we can return with all new messages
                List<Message> newMessages = new List<Message>();

                // All the new messages not seen by the POP3 client
                for (int i = 0; i < uids.Count; i++)
                {
                    string currentUidOnServer = uids[i];
                    if (!seenUids.Contains(currentUidOnServer))
                    {
                        // We have not seen this message before.
                        // Download it and add this new uid to seen uids

                        // the uids list is in messageNumber order - meaning that the first
                        // uid in the list has messageNumber of 1, and the second has 
                        // messageNumber 2. Therefore we can fetch the message using
                        // i + 1 since messageNumber should be in range [1, messageCount]
                        Message unseenMessage = client.GetMessage(i + 1);

                        // Add the message to the new messages
                        newMessages.Add(unseenMessage);

                        // Add the uid to the seen uids, as it has now been seen
                        seenUids.Add(currentUidOnServer);
                    }
                }

                // Return our new found messages
                return newMessages;
            }
        }
        protected void Getattachments(ref List<string> List, Message message)
        {
            List<MessagePart> attachments = message.FindAllAttachments();
            foreach (MessagePart attachment in attachments)
            {
                // Add the attachment to the list of attachments
                List.Add(attachment.FileName);
                // Keep a reference to the attachment in the Tag property

            }
        }
    }
}